#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/io.h>
#include <linux/device.h>
#include <linux/platform_device.h>

#include "mpu6050.h"

#define MYDEV_NAME "mpu6050"
#define MYDEV_COUNT 1

struct mpu6050_dev
{
    int major;
    int minor;
    dev_t devid;                                    //设备号
    struct cdev cdev;                               //cdev
    struct class *class;                            //类
    struct device *device;  
    struct device_node *nd;                        //设备
    void *private_data;
    struct i2c_client *client;
};
static struct mpu6050_dev mpu6050;

static int reg_read(struct i2c_client *client, u8 address , void *data, u32 length)
{
    int ret;
    struct i2c_msg msg[2];

    msg[0].addr = client->addr;
    msg[0].flags = 0;
    msg[0].len = 1;
    msg[0].buf = &address;

    msg[1].addr = client->addr;
    msg[1].flags = I2C_M_RD;
    msg[1].len = length;
    msg[1].buf = data;

    ret = i2c_transfer(client->adapter, msg, 2);
    if (ret < 0)
    {
        printk("i2c_transfer error\n");
        return -1;
    }
    return 0;

}
static int reg_write(struct i2c_client *client, u8 address, u8 data )
{
    int ret;
    u8 writebuf[2]={0};
    struct i2c_msg sendmsg;

    writebuf[0] = address;
    writebuf[1] = data;

    sendmsg.addr = client->addr;
    sendmsg.flags = 0;
    sendmsg.len = 2;
    sendmsg.buf = writebuf;

    ret = i2c_transfer(client->adapter, &sendmsg, 1);
    if (ret < 0)
    {
        printk("i2c_transfer error\n");
        return -1;
    }
    return 0;
}

static int mympu6050_init(void)
{
    int ret = 0;
    ret += reg_write(mpu6050.client, PWR_MGMT_1, 0X00);
	ret += reg_write(mpu6050.client, SMPLRT_DIV, 0X07);
	ret += reg_write(mpu6050.client, CONFIG, 0X06);
	ret += reg_write(mpu6050.client, ACCEL_CONFIG, 0X01);

    if (ret < 0)
    {
        printk("mpu6050 init error\n");
        return -1;
    }
    return 0;
}
static int mpu6050_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &mpu6050;
    printk("111");
    mympu6050_init();
    return 0;
}

static int mpu6050_release(struct inode *inode, struct file *filp)
{
    return 0;
}

static ssize_t mpu6050_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    char hdata=0;
    char ldata=0;
    int ret = 0;
    short msgchar[6];

    reg_read(mpu6050.client,ACCEL_XOUT_H, &hdata, 1);
    reg_read(mpu6050.client,ACCEL_XOUT_L, &ldata, 1);
    msgchar[0] = (hdata<<8)|ldata;
    reg_read(mpu6050.client,ACCEL_YOUT_H, &hdata, 1);
    reg_read(mpu6050.client,ACCEL_YOUT_L, &ldata, 1);
    msgchar[1] = (hdata<<8)|ldata;
    reg_read(mpu6050.client,ACCEL_ZOUT_H, &hdata, 1);
    reg_read(mpu6050.client,ACCEL_ZOUT_L, &ldata, 1);
    msgchar[2] = (hdata<<8)|ldata;
    reg_read(mpu6050.client,GYRO_XOUT_H, &hdata, 1);
    reg_read(mpu6050.client,GYRO_XOUT_L, &ldata, 1);
    msgchar[3] = (hdata<<8)|ldata;
    reg_read(mpu6050.client,GYRO_YOUT_H, &hdata, 1);
    reg_read(mpu6050.client,GYRO_YOUT_L, &ldata, 1);
    msgchar[4] = (hdata<<8)|ldata;
    reg_read(mpu6050.client,GYRO_ZOUT_H, &hdata, 1);
    reg_read(mpu6050.client,GYRO_ZOUT_L, &ldata, 1);
    msgchar[5] = (hdata<<8)|ldata;

    ret=copy_to_user(buf, msgchar, cnt);
    return 0;
        
    
}


static struct file_operations mpu6050_fops =
{
    .owner = THIS_MODULE,
    .open = mpu6050_open,
    .release = mpu6050_release,
    .read = mpu6050_read,
};

static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id)
{

    printk("000");
    alloc_chrdev_region(&mpu6050.devid, 0, MYDEV_COUNT, MYDEV_NAME);
    printk("111");
    mpu6050.major = MAJOR(mpu6050.devid);
    mpu6050.minor = MINOR(mpu6050.devid);
    printk("222");
    cdev_init(&mpu6050.cdev, &mpu6050_fops);
    printk("333");
    cdev_add(&mpu6050.cdev, mpu6050.devid, MYDEV_COUNT);
    printk("444");
    mpu6050.class = class_create(THIS_MODULE, MYDEV_NAME);
    printk("555");
    mpu6050.device = device_create(mpu6050.class, NULL, mpu6050.devid, NULL, MYDEV_NAME);
    printk("666");
    mpu6050.client = client;
    printk("777");
    return 0;
}

static int mpu6050_remove(struct i2c_client *client)
{
    device_destroy(mpu6050.class, MKDEV(mpu6050.major, mpu6050.minor));
    class_destroy(mpu6050.class);
    cdev_del(&mpu6050.cdev);
    unregister_chrdev_region(MKDEV(mpu6050.major, mpu6050.minor), MYDEV_COUNT);
    return 0;
}

static const struct i2c_device_id mpu6050_id[] = {
	{"xby,mpu6050", 0},
	{}};

static const struct of_device_id mpu6050_of_match[] =
{
    {.compatible = "xby,mpu6050"},
    {/* sentinel */}
};

static struct i2c_driver mpu6050_driver =
{
    .probe = mpu6050_probe,
    .remove = mpu6050_remove,
    .id_table = mpu6050_id,
    .driver =
    {
        .name = "mpu6050",
        .owner = THIS_MODULE,
        .of_match_table = mpu6050_of_match,
    },
};

static int __init mpu6050_init(void)
{
    int ret=0;
    ret = i2c_add_driver(&mpu6050_driver);
    return ret;
}

static void __exit mpu6050_exit(void)
{
    i2c_del_driver(&mpu6050_driver);
}

module_init(mpu6050_init);
module_exit(mpu6050_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xby");